/**
 * @file
 * Expansion graph instance test
 */

#include "instance_isomorphism.h"
#include "expansion_graph_instance_test.h"


void ExpansionGraphInstanceTest::SetUp()
{
  ExpansionGraphTest::SetUp();
  g1_i1 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i1->add_vertex(g1_v1);
  g1_i1->add_vertex(g1_v8);
  g1_i1->add_vertex(g1_v9);
  g1_i1->add_edge(g1_e11);
  g1_i1->add_edge(g1_e9);
  g1_i1->add_edge(g1_e8);

  g1_i2 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i2->add_vertex(g1_v1);
  g1_i2->add_vertex(g1_v8);
  g1_i2->add_vertex(g1_v7);
  g1_i2->add_edge(g1_e11);
  g1_i2->add_edge(g1_e10);
  g1_i2->add_edge(g1_e7);

  g1_i3 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i3->add_vertex(g1_v1);
  g1_i3->add_vertex(g1_v8);
  g1_i3->add_vertex(g1_v7);
  g1_i3->add_vertex(g1_v9);
  g1_i3->add_edge(g1_e11);
  g1_i3->add_edge(g1_e10);
  g1_i3->add_edge(g1_e7);
  g1_i3->add_edge(g1_e8);

  g1_i4 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i4->add_vertex(g1_v1);
  g1_i4->add_vertex(g1_v8);
  g1_i4->add_vertex(g1_v7);
  g1_i4->add_vertex(g1_v9);
  g1_i4->add_edge(g1_e11);
  g1_i4->add_edge(g1_e8);
  g1_i4->add_edge(g1_e7);
  g1_i4->add_edge(g1_e9);

  g1_i5 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i5->add_vertex(g1_v1);
  g1_i5->add_vertex(g1_v8);
  g1_i5->add_vertex(g1_v7);
  g1_i5->add_vertex(g1_v6);
  g1_i5->add_edge(g1_e11);
  g1_i5->add_edge(g1_e10);
  g1_i5->add_edge(g1_e7);
  g1_i5->add_edge(g1_e6);

  g1_i6 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i6->add_vertex(g1_v1);
  g1_i6->add_vertex(g1_v8);
  g1_i6->add_vertex(g1_v9);
  g1_i6->add_vertex(g1_v2);
  g1_i6->add_edge(g1_e11);
  g1_i6->add_edge(g1_e9);
  g1_i6->add_edge(g1_e1);
  g1_i6->add_edge(g1_e8);


  g1_i7 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i7->add_vertex(g1_v1);
  g1_i7->add_vertex(g1_v2);
  g1_i7->add_vertex(g1_v7);
  g1_i7->add_vertex(g1_v8);
  g1_i7->add_edge(g1_e1);
  g1_i7->add_edge(g1_e10);
  g1_i7->add_edge(g1_e11);
  g1_i7->add_edge(g1_e7);


  g1_i8 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i8->add_vertex(g1_v1);
  g1_i8->add_vertex(g1_v7);
  g1_i8->add_vertex(g1_v8);
  g1_i8->add_vertex(g1_v9);
  g1_i8->add_edge(g1_e10);
  g1_i8->add_edge(g1_e11);
  g1_i8->add_edge(g1_e9);
  g1_i8->add_edge(g1_e8);

  g1_i9 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i9->add_vertex(g1_v1);
  g1_i9->add_vertex(g1_v7);
  g1_i9->add_vertex(g1_v8);
  g1_i9->add_vertex(g1_v9);
  g1_i9->add_edge(g1_e10);
  g1_i9->add_edge(g1_e11);
  g1_i9->add_edge(g1_e9);
  g1_i9->add_edge(g1_e7);

  g1_i10 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g1);
  g1_i10->add_vertex(g1_v1);
  g1_i10->add_vertex(g1_v7);
  g1_i10->add_vertex(g1_v8);
  g1_i10->add_vertex(g1_v9);
  g1_i10->add_edge(g1_e10);
  g1_i10->add_edge(g1_e11);
  g1_i10->add_edge(g1_e9);
  g1_i10->add_edge(g1_e8);
  g1_i10->add_edge(g1_e7);


  g2_i1 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i1->add_vertex(g2_v1);
  g2_i1->add_vertex(g2_v8);
  g2_i1->add_vertex(g2_v9);
  g2_i1->add_edge(g2_e11);
  g2_i1->add_edge(g2_e9);
  g2_i1->add_edge(g2_e8);

  g2_i2 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i2->add_vertex(g2_v1);
  g2_i2->add_vertex(g2_v8);
  g2_i2->add_vertex(g2_v7);
  g2_i2->add_edge(g2_e11);
  g2_i2->add_edge(g2_e10);
  g2_i2->add_edge(g2_e7);

  g2_i3 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i3->add_vertex(g2_v1);
  g2_i3->add_vertex(g2_v8);
  g2_i3->add_vertex(g2_v7);
  g2_i3->add_vertex(g2_v9);
  g2_i3->add_edge(g2_e11);
  g2_i3->add_edge(g2_e10);
  g2_i3->add_edge(g2_e7);
  g2_i3->add_edge(g2_e8);

  g2_i4 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i4->add_vertex(g2_v1);
  g2_i4->add_vertex(g2_v8);
  g2_i4->add_vertex(g2_v7);
  g2_i4->add_vertex(g2_v9);
  g2_i4->add_edge(g2_e11);
  g2_i4->add_edge(g2_e8);
  g2_i4->add_edge(g2_e7);
  g2_i4->add_edge(g2_e9);

  g2_i5 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i5->add_vertex(g2_v1);
  g2_i5->add_vertex(g2_v8);
  g2_i5->add_vertex(g2_v7);
  g2_i5->add_vertex(g2_v6);
  g2_i5->add_edge(g2_e11);
  g2_i5->add_edge(g2_e10);
  g2_i5->add_edge(g2_e7);
  g2_i5->add_edge(g2_e6);

  g2_i6 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i6->add_vertex(g2_v1);
  g2_i6->add_vertex(g2_v8);
  g2_i6->add_vertex(g2_v9);
  g2_i6->add_vertex(g2_v2);
  g2_i6->add_edge(g2_e11);
  g2_i6->add_edge(g2_e9);
  g2_i6->add_edge(g2_e1);
  g2_i6->add_edge(g2_e8);


  g2_i7 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i7->add_vertex(g2_v1);
  g2_i7->add_vertex(g2_v2);
  g2_i7->add_vertex(g2_v7);
  g2_i7->add_vertex(g2_v8);
  g2_i7->add_edge(g2_e1);
  g2_i7->add_edge(g2_e10);
  g2_i7->add_edge(g2_e11);
  g2_i7->add_edge(g2_e7);


  g2_i8 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i8->add_vertex(g2_v1);
  g2_i8->add_vertex(g2_v7);
  g2_i8->add_vertex(g2_v8);
  g2_i8->add_vertex(g2_v9);
  g2_i8->add_edge(g2_e10);
  g2_i8->add_edge(g2_e11);
  g2_i8->add_edge(g2_e9);
  g2_i8->add_edge(g2_e8);

  g2_i9 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i9->add_vertex(g2_v1);
  g2_i9->add_vertex(g2_v7);
  g2_i9->add_vertex(g2_v8);
  g2_i9->add_vertex(g2_v9);
  g2_i9->add_edge(g2_e10);
  g2_i9->add_edge(g2_e11);
  g2_i9->add_edge(g2_e9);
  g2_i9->add_edge(g2_e7);

  g2_i10 = new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(g2);
  g2_i10->add_vertex(g2_v1);
  g2_i10->add_vertex(g2_v7);
  g2_i10->add_vertex(g2_v8);
  g2_i10->add_vertex(g2_v9);
  g2_i10->add_edge(g2_e10);
  g2_i10->add_edge(g2_e11);
  g2_i10->add_edge(g2_e9);
  g2_i10->add_edge(g2_e8);
  g2_i10->add_edge(g2_e7);

}

void ExpansionGraphInstanceTest::TearDown()
{
  delete g1_i1;
  delete g1_i2;
  delete g1_i3;
  delete g1_i4;
  delete g1_i5;
  delete g1_i6;
  delete g1_i7;
  delete g1_i8;
  delete g1_i9;
  delete g1_i10;

  delete g2_i1;
  delete g2_i2;
  delete g2_i3;
  delete g2_i4;
  delete g2_i5;
  delete g2_i6;
  delete g2_i7;
  delete g2_i8;
  delete g2_i9;
  delete g2_i10;

  ExpansionGraphTest::TearDown();
}

TEST_F(ExpansionGraphInstanceTest, GetVertices)
{
  std::set<StringVertexEdge*> *actual;
  g1_i1->get_vertices(&actual);
  
  std::set<StringVertexEdge*> expected;
  expected.insert(g1_v1);
  expected.insert(g1_v8);
  expected.insert(g1_v9);
  
  EXPECT_TRUE(*actual == expected);
}

TEST_F(ExpansionGraphInstanceTest, GetEdges)
{
  std::set<StringVertexEdge*> *actual;
  g1_i1->get_edges(&actual);
  
  std::set<StringVertexEdge*> expected;
  expected.insert(g1_e11);
  expected.insert(g1_e9);
  expected.insert(g1_e8);

  EXPECT_TRUE(*actual == expected);
}

TEST_F(ExpansionGraphInstanceTest, GetConstrainedExpansions)
{
  std::map<StringVertexEdge*, StringVertexEdge*> actual;
  g1_i1->get_constrained_expansions(g1_v1, &actual);

  std::map<StringVertexEdge*, StringVertexEdge*> expected;
  expected.insert(std::pair<StringVertexEdge*, StringVertexEdge*>(g1_e11,g1_v8));
  expected.insert(std::pair<StringVertexEdge*, StringVertexEdge*>(g1_e9,g1_v9));

  EXPECT_TRUE(actual == expected);
}

TEST_F(ExpansionGraphInstanceTest, CheckAdjacency)
{
  EXPECT_TRUE(g1_i1->check_adjacency(g1_e11, g1_v1, g1_v9));
  EXPECT_TRUE(g1_i1->check_adjacency(g1_e8, g1_v8, g1_v9));
  EXPECT_TRUE(g1_i1->check_adjacency(g1_e9, g1_v1, g1_v9));
}

TEST_F(ExpansionGraphInstanceTest, EdgePresenceTest)
{
  EXPECT_TRUE(g1_i1->has_edge(g1_e11));
  EXPECT_TRUE(g1_i1->has_edge(g1_e9));
  EXPECT_TRUE(g1_i1->has_edge(g1_e8));

  EXPECT_FALSE(g1_i1->has_edge(g1_e1));
  EXPECT_FALSE(g1_i1->has_edge(g1_e2));
  EXPECT_FALSE(g1_i1->has_edge(g1_e3));
}

TEST_F(ExpansionGraphInstanceTest, CopyIdentityTest)
{
  ExpansionGraphInstance<StringVertexEdge, StringVertexEdge> *i_new =
    new ExpansionGraphInstance<StringVertexEdge, StringVertexEdge>(*g1_i1);
  ExpansionGraphInstanceIdentityEquivalence<StringVertexEdge, StringVertexEdge> comparison;
  EXPECT_TRUE(comparison(g1_i1, i_new));
  EXPECT_FALSE(comparison(g1_i2, i_new));
  delete i_new;
}

TEST_F(ExpansionGraphInstanceTest, ExpansionTest)
{
  std::list< ExpansionGraphInstance<StringVertexEdge, StringVertexEdge> * > expected;
  expected.push_back(g1_i4);
  expected.push_back(g1_i6);
  expected.push_back(g1_i8);
 
  std::list<ExpansionGraphInstance<StringVertexEdge, StringVertexEdge> *> actual;
  g1_i1->expand(&actual);

  ExpansionGraphInstanceIdentityEquivalence<StringVertexEdge, StringVertexEdge> comparison;

  EXPECT_TRUE(actual.size() == expected.size());

  for(std::list<ExpansionGraphInstance<StringVertexEdge, StringVertexEdge> *>::iterator i = expected.begin();
      i != expected.end();
      i++)
    {
      bool found = false;
      for(std::list<ExpansionGraphInstance<StringVertexEdge, StringVertexEdge> *>::iterator j = actual.begin();
          j != actual.end();)
        if( comparison( *i, *j) )
          {
            delete (*j);
            actual.erase(j++);
            found = true;
            break;
          }
        else
          j++;
      
      if (! found)
        ADD_FAILURE();
    }
  
  EXPECT_TRUE(actual.empty());
}

TEST_F(ExpansionGraphInstanceTest, CanonicalLabelTest)
{
  std::string *canonical_label1, *canonical_label2;
  
  canonical_label1 = new std::string;
  canonical_label2 = new std::string;

  *canonical_label1 = g1_i1->get_canonical_label();
  *canonical_label2 = g1_i2->get_canonical_label();
  
  EXPECT_TRUE(*canonical_label1 == *canonical_label2);

  delete canonical_label1;
  delete canonical_label2;

  canonical_label1 = new std::string;
  canonical_label2 = new std::string;

  *canonical_label1 = g1_i1->get_canonical_label();
  *canonical_label2 = g1_i3->get_canonical_label();
  
  EXPECT_FALSE(*canonical_label1 == *canonical_label2);

  delete canonical_label1;
  delete canonical_label2;

  canonical_label1 = new std::string;
  canonical_label2 = new std::string;

  *canonical_label1 = g1_i2->get_canonical_label();
  *canonical_label2 = g1_i3->get_canonical_label();
  
  EXPECT_FALSE(*canonical_label1 == *canonical_label2);

  delete canonical_label1;
  delete canonical_label2;

  canonical_label1 = new std::string;
  canonical_label2 = new std::string;

  *canonical_label1 = g1_i3->get_canonical_label();
  *canonical_label2 = g1_i4->get_canonical_label();
  
  EXPECT_TRUE(*canonical_label1 == *canonical_label2);

  delete canonical_label1;
  delete canonical_label2;

  canonical_label1 = new std::string;
  canonical_label2 = new std::string;

  *canonical_label1 = g1_i1->get_canonical_label();
  *canonical_label2 = g1_i2->get_canonical_label();
  
  EXPECT_TRUE(*canonical_label1 == *canonical_label2);

  delete canonical_label1;
  delete canonical_label2;

  canonical_label1 = new std::string;
  canonical_label2 = new std::string;

  *canonical_label1 = g1_i1->get_canonical_label();
  *canonical_label2 = g2_i3->get_canonical_label();
  
  EXPECT_FALSE(*canonical_label1 == *canonical_label2);

  delete canonical_label1;
  delete canonical_label2;

  canonical_label1 = new std::string;
  canonical_label2 = new std::string;

  *canonical_label1 = g1_i2->get_canonical_label();
  *canonical_label2 = g2_i3->get_canonical_label();
  
  EXPECT_FALSE(*canonical_label1 == *canonical_label2);

  delete canonical_label1;
  delete canonical_label2;

  canonical_label1 = new std::string;
  canonical_label2 = new std::string;

  *canonical_label1 = g1_i3->get_canonical_label();
  *canonical_label2 = g2_i4->get_canonical_label();
  
  EXPECT_TRUE(*canonical_label1 == *canonical_label2);

  delete canonical_label1;
  delete canonical_label2;

}  
